package com.yc.cinema.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * 切面 = 增强 + 切点
 */
@Aspect
@Component
public class MyAspect {

    /**
     * 定义切点
     * Aspect 表达式
     */
    @Pointcut("execution(* com.yc.cinema.biz.*.*(..))")
    public void pointcut() {
    }

    /**
     * 定义增强(通知)
     * 前置增强
     * JoinPoint jp 连接点对象 ( 被拦截到的方法 )
     */
    @Before("execution(* com.yc.cinema.web.*.*(..))")
    public void before(JoinPoint jp) {
        System.out.println("------前置增强------");
        System.out.println("方法签名: " + jp.getSignature());
        System.out.println("调用方法传入的参数:" + Arrays.toString(jp.getArgs()));
    }

    /**
     * 后置增强
     *
     * @param jp
     */
    @After("pointcut()")
    public void after(JoinPoint jp) {
        System.out.println("------后置增强------");
        System.out.println("方法签名: " + jp.getSignature());
        System.out.println("调用方法传入的参数:" + Arrays.toString(jp.getArgs()));
    }

    /**
     * 返回增强, 业务方法执行完之后, 返回方法返回值, 进行的增强
     * MyBatis 的多参数 , 使用 @Param 定义参数名
     * Aspect 可以获取到参数变量名   更强大
     */
    @AfterReturning(pointcut = "pointcut()", returning = "ret")
    public void retruning(JoinPoint jp, Object ret) {
        System.out.println("------返回增强------");
        System.out.println("方法签名: " + jp.getSignature());
        System.out.println("调用方法传入的参数:" + Arrays.toString(jp.getArgs()));
        System.out.println("业务方法的返回值: " + ret);
    }

    @AfterThrowing(pointcut = "pointcut()", throwing = "t")
    public void throwing(JoinPoint jp, Throwable t) {
        System.out.println("------异常增强------");
        System.out.println("方法签名: " + jp.getSignature());
        System.out.println("调用方法传入的参数:" + Arrays.toString(jp.getArgs()));
        System.out.println("业务方法产生的异常: " + t);
    }

    //@Around("pointcut()")
    public Object around(ProceedingJoinPoint pjp) {
        /**
         环绕增强的特殊性
         1. 连接点   ProceedingJoinPoint
         2. 业务方法手动执行
         *
         */
        // 执行被拦截业务方法0``
        try {
            long time = System.currentTimeMillis();
            System.out.println("------环绕增强------");
            Object ret = pjp.proceed();
            time = System.currentTimeMillis() - time;
            System.out.println("方法签名: " + pjp.getSignature());
            System.out.println("调用方法传入的参数:" + Arrays.toString(pjp.getArgs()));
            System.out.println("业务方法的返回值: " + ret);
            System.out.println("共耗时:" + time);
            return ret;
        } catch (Throwable throwable) {
            System.out.println("业务方法产生的异常: " + throwable);
            throwable.printStackTrace();
            return null;
        }

    }


}
